/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frstat_server.c                                    */
/*  NOTE      =                                                    */
/*  DATE      = 2015/01/26 by guojq                                */
/*******************************************************************/
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/time.h>

#include "frcomm.h"
#include "frlog.h"
#include "frmem.h"
#include "frhash2.h"
#include "frame_params.h"

typedef struct __conn_info {
    unsigned long ul_connections;
    unsigned long ul_requests;
    unsigned long ul_responses;
} conn_info;

typedef struct __conn_avg {
    unsigned long ul_connections[4];
    unsigned long ul_requests[4];
    unsigned long ul_responses[4];
} conn_avg;

typedef struct __server_info {
    u_int   ui_ip;
    u_short us_port;
    int     i_l7_proto;
    
    struct timeval start_time;
    conn_info st_conns_total;
    conn_avg  st_conns_avg;
} Server_info;

//端口关联表
typedef struct __port_related {
    u_int   ui_ip;
    u_short us_port;
    u_int   ui_ip_related;
    u_short us_port_related;
    
    struct timeval start_time;
} Port_related;

//做完关联后的hash节点
typedef struct __server_info_avg {
    u_int   ui_ip;
    u_short us_port;
    int     i_l7_proto;
    
    unsigned long ul_connections;
    unsigned long ul_requests;
    unsigned long ul_responses;
    
    unsigned long ul_connections_avg;
    unsigned long ul_requests_avg;
    unsigned long ul_responses_avg;
} Server_info_avg; 

static Frhash_header g_st_hash_server;
static Frhash_header g_st_hash_related;
static pthread_rwlock_t g_stat_server_rwlock;
static int g_i_timeout = 1;
static int g_i_flag_init = FR_FAIL;

/*******************************************************************************
*  FUNC     :  释放节点内容
*  ARGS     :  p_node 
*  RTN      :
*  NOTE     :  
*******************************************************************************/
static void __server_node_free(Frlist_node* p_node)
{
    Server_info *p_stat_node = NULL;
    
    if (p_node && p_node->data)
    {
        p_stat_node = (Server_info *)p_node->data;
        frfree(p_stat_node);
    }
}

/*******************************************************************************
*  FUNC     :  释放关联信息节点内容
*  ARGS     :  p_node 
*  RTN      :
*  NOTE     :  
*******************************************************************************/
static void __related_node_free(Frlist_node* p_node)
{
    Port_related *p_stat_node = NULL;
    
    if (p_node && p_node->data)
    {
        p_stat_node = (Port_related *)p_node->data;
        frfree(p_stat_node);
    }
}

/*******************************************************************************
*  FUNC     :  释放打印信息节点内容
*  ARGS     :  p_node 
*  RTN      :
*  NOTE     :  
*******************************************************************************/
static void __outhash_node_free(Frlist_node* p_node)
{
    Server_info_avg *p_stat_node = NULL;
    
    if (p_node && p_node->data)
    {
        p_stat_node = (Server_info_avg *)p_node->data;
        frfree(p_stat_node);
    }
}

/*******************************************************************************
*  FUNC     :  组成哈希用key
*  ARGS     :  ui_ip        (ip地址)
*           :  us_port      (端口)
*           :  i_l7_proto   (l7协议名)
*           :  p_key        (保存地址)
*           :  ui_key_size  (保存地址长度)
*  RTN      :  key长度
*  NOTE     :
*******************************************************************************/
static int __frhash_make_key(u_int ui_ip, u_short us_port, int i_l7_proto
                              , char *p_key, unsigned int ui_key_size)
{
    int i_idx=0;
    int *stupid_strict_aliasing_warnings=(int*)p_key;

    if(p_key == NULL || ui_key_size <= sizeof(u_int) + sizeof(int) + sizeof(u_short))
    {
        FRLOG_ERROR_DETAIL("expect hash key err");
        return 0;
    }
    *stupid_strict_aliasing_warnings = i_l7_proto;
    i_idx += sizeof(int);
    *(u_int *) (p_key + i_idx) = ui_ip;
    i_idx += sizeof(u_int);
    *(u_short *) (p_key + i_idx) = us_port;
    i_idx += sizeof(u_short);
    
    return i_idx;
}

/*******************************************************************************
*  FUNC     :  添加服务节点信息
*  ARGS     :  ui_ip                (ip地址)
*           :  us_port              (端口)
*           :  i_l7_proto           (l7协议名)
*           :  i_connections        (连接数)
*           :  i_requests           (request数)
*           :  i_responses          (response数)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
int frstat_server_add(u_int ui_ip, u_short us_port, int i_l7_proto
                    , int i_connections, int i_requests, int i_responses)
{
    Frlist_node *p_st_node = NULL;
    Server_info *p_server_info = NULL;
    char arr_hash_key[25] = {'\0'};
    int i_hash_key_len = 0;

    if(g_i_flag_init == FR_FAIL)
        return FR_FAIL;
    
    i_hash_key_len = __frhash_make_key(ui_ip, us_port, i_l7_proto, arr_hash_key, sizeof(arr_hash_key));
    if (i_hash_key_len == 0)
        return FR_FAIL;
    
    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    
    p_st_node = frhash2_getStr(&g_st_hash_server, arr_hash_key, i_hash_key_len);
    if (p_st_node && p_st_node->data)
    {
        p_server_info = (Server_info *)p_st_node->data;
        
        p_server_info->st_conns_total.ul_connections += i_connections;
        p_server_info->st_conns_total.ul_requests += i_requests;
        p_server_info->st_conns_total.ul_responses += i_responses;
        
        pthread_rwlock_unlock(&g_stat_server_rwlock);
        return FR_SUCC;
    }
    p_server_info = frmalloc(sizeof(Server_info));
    if (p_server_info == NULL)
    {
        pthread_rwlock_unlock(&g_stat_server_rwlock);
        return FR_FAIL;
    }
    memset(p_server_info, 0x00, sizeof(Server_info));
    
    p_server_info->ui_ip = ui_ip;
    p_server_info->us_port = us_port;
    p_server_info->i_l7_proto = i_l7_proto;
    
    p_server_info->st_conns_total.ul_connections = i_connections;
    p_server_info->st_conns_total.ul_requests = i_requests;
    p_server_info->st_conns_total.ul_responses = i_responses;
    
    gettimeofday(&p_server_info->start_time, 0);
    
    p_st_node = frlist_node_create(p_server_info);
    if (p_st_node == NULL)
    {
        frfree(p_server_info);
        pthread_rwlock_unlock(&g_stat_server_rwlock);
        return FR_FAIL;
    }
    frhash2_addStr(&g_st_hash_server, arr_hash_key, i_hash_key_len, p_st_node);
    
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除服务节点信息
*  ARGS     :  ui_ip                (ip地址)
*           :  us_port              (端口)
*           :  i_l7_proto           (l7协议名)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
int frstat_server_del(u_int ui_ip, u_short us_port, int i_l7_proto)
{
    char arr_hash_key[25] = {'\0'};
    int i_hash_key_len = 0;

    if(g_i_flag_init == FR_FAIL)
        return FR_FAIL;
    
    i_hash_key_len = __frhash_make_key(ui_ip, us_port, i_l7_proto, arr_hash_key, sizeof(arr_hash_key));
    if (i_hash_key_len == 0)
        return FR_FAIL;
        
    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    frhash2_delStr(&g_st_hash_server, arr_hash_key, i_hash_key_len, __server_node_free);
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  检查服务节点是否过期
*  ARGS     :  i_timeout            过期时间(秒)
*  RTN      :  
*  NOTE     :
*******************************************************************************/
void frstat_server_check_timeouts(int i_timeout)
{
    int i_loop=0;
    Frlist_header *p_st_lst_hdr = NULL;
    Frlist_node *p_st_node = NULL;
    Frlist_node *p_st_next = NULL;
    Server_info *p_server_info_node = NULL;
    struct timeval st_now;

    if(g_i_flag_init == FR_FAIL)
        return;
    
    gettimeofday(&st_now, 0);
    
    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    FRHASH_LOOP(i_loop, &g_st_hash_server, p_st_lst_hdr)
    {
        p_st_node = FRLIST_FIRST_NODE(p_st_lst_hdr);
        while(p_st_node)
        {
            p_st_next = FRLIST_NEXT_NODE(p_st_node);
            if(p_st_node && p_st_node->data)
            {
                p_server_info_node = (Server_info *)(p_st_node->data);
                if (st_now.tv_sec - p_server_info_node->start_time.tv_sec > i_timeout)
                {
                    frlist_node_free(p_st_lst_hdr, p_st_node, 1, __server_node_free);
                }
            }
            p_st_node = p_st_next;
        }
    }
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    
    return;
}

/*******************************************************************************
*  FUNC     :  计算节点的平均信息
*  ARGS     :  p_node               线程节点
*           :  p_data               节点的信息
*  RTN      :  1 继续做下一个节点
*  NOTE     :  
*******************************************************************************/
static int __frstat_server_count(Frlist_node* p_node, const void *p_data)
{
    Server_info *p_stat_node = NULL;
    
    p_stat_node = (Server_info *)p_node->data;
    
    memmove(p_stat_node->st_conns_avg.ul_connections + 1, p_stat_node->st_conns_avg.ul_connections, sizeof(unsigned long)*3);
    memmove(p_stat_node->st_conns_avg.ul_requests + 1, p_stat_node->st_conns_avg.ul_requests, sizeof(unsigned long)*3);
    memmove(p_stat_node->st_conns_avg.ul_responses + 1, p_stat_node->st_conns_avg.ul_responses, sizeof(unsigned long)*3);
    
    p_stat_node->st_conns_avg.ul_connections[0] = p_stat_node->st_conns_total.ul_connections;
    p_stat_node->st_conns_avg.ul_requests[0] = p_stat_node->st_conns_total.ul_requests;
    p_stat_node->st_conns_avg.ul_responses[0] = p_stat_node->st_conns_total.ul_responses;
    
    return 1;
}

/*******************************************************************************
*  FUNC     :  计算所有服务节点的平均信息
*  ARGS     :  
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void frstat_server_count(void)
{
    if(g_i_flag_init == FR_FAIL)
        return ;

    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    frhash2_run(&g_st_hash_server, NULL, __frstat_server_count);
    pthread_rwlock_unlock(&g_stat_server_rwlock);
}

/*******************************************************************************
*  FUNC     :  计算平均值
*  ARGS     :  arr_ul_last          总数表
*           :  p_avg                算好的平均值
*  RTN      :
*  NOTE     :
*******************************************************************************/
static void __count_avg(unsigned long arr_ul_last[4], unsigned long *p_avg)
{
    if (arr_ul_last[0] == 0 || arr_ul_last[1] == 0)
    {
        //记录的是总数，因此前2个节点为0的情况说明平均为0或者是刚开始统计，平均设成0
        *p_avg = 0;
        return;
    }
    if (arr_ul_last[2] == 0)
    {
        *p_avg = (arr_ul_last[0] - arr_ul_last[1])/g_i_timeout;
        return;
    }
    if (arr_ul_last[3] == 0)
    {
        *p_avg = (arr_ul_last[0] - arr_ul_last[2])/(g_i_timeout*2);
        return;
    }
    *p_avg = (arr_ul_last[0] - arr_ul_last[3])/(g_i_timeout*3);
    return;
}

/*******************************************************************************
*  FUNC     :  显示一个服务节点的信息
*  ARGS     :  p_node               服务节点
*           :  p_outbuff            出力内容
*           :  ui_outlen            出力长度
*  RTN      :  
*  NOTE     :  
*******************************************************************************/
void __frstat_server_output(Frlist_node* p_node, char *p_outbuff, unsigned int ui_outlen)
{
    Server_info_avg *p_stat_node = NULL;
    
    p_stat_node = (Server_info_avg *)p_node->data;
    
    snprintf(p_outbuff, ui_outlen
           , "ip=%s, port=%u, l7_proto=%d, connections=%lu(%lu/s), requests=%lu(%lu/s), responses=%lu(%lu/s)\n"
           , int_ntoa(p_stat_node->ui_ip)
           , p_stat_node->us_port
           , p_stat_node->i_l7_proto
           , p_stat_node->ul_connections, p_stat_node->ul_connections_avg
           , p_stat_node->ul_requests, p_stat_node->ul_requests_avg
           , p_stat_node->ul_responses, p_stat_node->ul_responses_avg);
    
    return;
}

/*******************************************************************************
*  FUNC     :  组成合并关联哈希用key
*  ARGS     :  ui_ip        (ip地址)
*           :  us_port      (端口)
*           :  i_l7_proto   (l7协议名)
*           :  p_key        (保存地址)
*           :  ui_key_size  (保存地址长度)
*  RTN      :  key长度
*  NOTE     :
*******************************************************************************/
static int __frhash_related_make_key(u_int ui_ip, u_short us_port, char *p_key, unsigned int ui_key_size)
{
    int i_idx=0;
    u_int *stupid_strict_aliasing_warnings=(u_int*)p_key;

    if(p_key == NULL || ui_key_size <= sizeof(u_int) + sizeof(u_short))
    {
        FRLOG_ERROR_DETAIL("expect hash key err");
        return 0;
    }
    *stupid_strict_aliasing_warnings = ui_ip;
    i_idx += sizeof(u_int);
    *(u_short *) (p_key + i_idx) = us_port;
    i_idx += sizeof(u_short);
    
    return i_idx;
}

/*******************************************************************************
*  FUNC     :  添加关联信息hash表
*  ARGS     :  ui_ip                (ip地址)
*           :  us_port              (端口)
*           :  ui_ip_related        (关联ip地址)
*           :  us_port_related      (关联端口)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
int frstat_server_related_add(u_int ui_ip, u_short us_port
                            , u_int ui_ip_related, u_short us_port_related)
{
    Frlist_node *p_st_node = NULL;
    Port_related *p_st_related_info = NULL;
    char arr_hash_key[20] = {'\0'};
    int i_hash_key_len = 0;
    
    if(g_i_flag_init == FR_FAIL)
        return FR_FAIL;

    i_hash_key_len = __frhash_related_make_key(ui_ip, us_port, arr_hash_key, sizeof(arr_hash_key));
    if (i_hash_key_len == 0)
    {
        //不可能发生
        return FR_FAIL;
    }
    
    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    
    p_st_node = frhash2_getStr(&g_st_hash_related, arr_hash_key, i_hash_key_len);
    if (p_st_node && p_st_node->data)
    {
        p_st_related_info = (Port_related *)p_st_node->data;
        
        FRLOG_WARN_DETAIL("frstat_server related add the same ip port?\n");
        p_st_related_info->ui_ip_related = ui_ip_related;
        p_st_related_info->us_port_related = us_port_related;
        
        pthread_rwlock_unlock(&g_stat_server_rwlock);
        return FR_SUCC;
    }
    p_st_related_info = frmalloc(sizeof(Port_related));
    if (p_st_related_info == NULL)
    {
        pthread_rwlock_unlock(&g_stat_server_rwlock);
        return FR_FAIL;
    }
    memset(p_st_related_info, 0x00, sizeof(Port_related));
    
    p_st_related_info->ui_ip = ui_ip;
    p_st_related_info->us_port = us_port;
    p_st_related_info->ui_ip_related = ui_ip_related;
    p_st_related_info->us_port_related = us_port_related;
    
    gettimeofday(&p_st_related_info->start_time, 0);
    
    p_st_node = frlist_node_create(p_st_related_info);
    if (p_st_node == NULL)
    {
        frfree(p_st_related_info);
        pthread_rwlock_unlock(&g_stat_server_rwlock);
        return FR_FAIL;
    }
    frhash2_addStr(&g_st_hash_related, arr_hash_key, i_hash_key_len, p_st_node);
    
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  删除关联信息节点
*  ARGS     :  ui_ip                (ip地址)
*           :  us_port              (端口)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
int frstat_server_related_del(u_int ui_ip, u_short us_port)
{
    char arr_hash_key[25] = {'\0'};
    int i_hash_key_len = 0;
    
    if(g_i_flag_init == FR_FAIL)
        return FR_FAIL;

    i_hash_key_len = __frhash_related_make_key(ui_ip, us_port, arr_hash_key, sizeof(arr_hash_key));
    if (i_hash_key_len == 0)
        return FR_FAIL;
        
    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    frhash2_delStr(&g_st_hash_related, arr_hash_key, i_hash_key_len, __related_node_free);
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  检查关联节点是否过期
*  ARGS     :  i_timeout            过期时间(秒)
*  RTN      :  
*  NOTE     :
*******************************************************************************/
void frstat_related_check_timeouts(int i_timeout)
{
    int i_loop=0;
    Frlist_header *p_st_lst_hdr = NULL;
    Frlist_node *p_st_node = NULL;
    Frlist_node *p_st_next = NULL;
    Port_related *p_related_node = NULL;
    struct timeval st_now;

    if(g_i_flag_init == FR_FAIL)
        return;
    
    gettimeofday(&st_now, 0);
    
    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    FRHASH_LOOP(i_loop, &g_st_hash_related, p_st_lst_hdr)
    {
        p_st_node = FRLIST_FIRST_NODE(p_st_lst_hdr);
        while(p_st_node)
        {
            p_st_next = FRLIST_NEXT_NODE(p_st_node);
            if(p_st_node && p_st_node->data)
            {
                p_related_node = (Port_related *)(p_st_node->data);
                if (st_now.tv_sec - p_related_node->start_time.tv_sec > i_timeout)
                {
                    frlist_node_free(p_st_lst_hdr, p_st_node, 1, __related_node_free);
                }
            }
            p_st_node = p_st_next;
        }
    }
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    
    return;
}

/*******************************************************************************
*  FUNC     :  添加打印hash的信息
*  ARGS     :  p_st_hash            (保存的hash)
*           :  ui_ip                (ip地址)
*           :  us_port              (端口)
*           :  i_l7_proto           (l7协议名)
*           :  ul_connections       (连接总数)
*           :  ul_requests          (request总数)
*           :  ul_responses         (response总数)
*           :  ul_connections_avg   (连接平均数)
*           :  ul_requests_avg      (request平均数)
*           :  ul_responses_avg     (response平均数)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
static int __frstat_outhash_add(Frhash_header *p_st_hash, u_int ui_ip, u_short us_port, int i_l7_proto
                                , unsigned long ul_connections, unsigned long ul_requests, unsigned long ul_responses
                                , unsigned long ul_connections_avg, unsigned long ul_requests_avg, unsigned long ul_responses_avg)
{
    Frlist_node *p_st_node = NULL;
    Server_info_avg *p_st_out_info = NULL;
    char arr_hash_key[20] = {'\0'};
    int i_hash_key_len = 0;
    
    i_hash_key_len = __frhash_make_key(ui_ip, us_port, i_l7_proto, arr_hash_key, sizeof(arr_hash_key));
    if (i_hash_key_len == 0)
    {
        //不可能发生
        return FR_FAIL;
    }
    
    p_st_node = frhash2_getStr(p_st_hash, arr_hash_key, i_hash_key_len);
    if (p_st_node && p_st_node->data)
    {
        //在打印hash中找到节点
        p_st_out_info = (Server_info_avg *)p_st_node->data;
        
        p_st_out_info->ul_connections += ul_connections;
        p_st_out_info->ul_requests += ul_requests;
        p_st_out_info->ul_responses += ul_responses;
        
        p_st_out_info->ul_connections_avg += ul_connections_avg;
        p_st_out_info->ul_requests_avg += ul_requests_avg;
        p_st_out_info->ul_responses_avg += ul_responses_avg;
        
        return FR_SUCC;
    }
    p_st_out_info = frmalloc(sizeof(Server_info_avg));
    if (p_st_out_info == NULL)
    {
        return FR_FAIL;
    }
    memset(p_st_out_info, 0x00, sizeof(Server_info_avg));
    
    p_st_out_info->ui_ip = ui_ip;
    p_st_out_info->us_port = us_port;
    p_st_out_info->i_l7_proto = i_l7_proto;
    
    p_st_out_info->ul_connections = ul_connections;
    p_st_out_info->ul_requests = ul_requests;
    p_st_out_info->ul_responses = ul_responses;
    p_st_out_info->ul_connections_avg = ul_connections_avg;
    p_st_out_info->ul_requests_avg = ul_requests_avg;
    p_st_out_info->ul_responses_avg = ul_responses_avg;
        
    p_st_node = frlist_node_create(p_st_out_info);
    if (p_st_node == NULL)
    {
        frfree(p_st_out_info);
        return FR_FAIL;
    }
    frhash2_addStr(p_st_hash, arr_hash_key, i_hash_key_len, p_st_node);
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  根据合并列表，做服务节点合并
*  ARGS     :  p_node               服务节点
*           :  p_data               合并后的hash表头
*  RTN      :  1 继续做下一个节点
*  NOTE     :  
*******************************************************************************/
static int __frstat_do_related(Frlist_node* p_node, const void *p_data)
{
    Server_info *p_stat_node = NULL;
    unsigned long ul_connections_avg = 0;
    unsigned long ul_requests_avg = 0;
    unsigned long ul_responses_avg = 0;
    Frlist_node *p_st_node = NULL;
    char arr_hash_key[20] = {'\0'};
    int i_hash_key_len = 0;
    u_int ui_ip = 0;
    u_short us_port = 0;
    Frhash_header *p_st_hash_print = (Frhash_header *)p_data;
    
    p_stat_node = (Server_info *)p_node->data;
    
    __count_avg(p_stat_node->st_conns_avg.ul_connections, &ul_connections_avg);
    __count_avg(p_stat_node->st_conns_avg.ul_requests, &ul_requests_avg);
    __count_avg(p_stat_node->st_conns_avg.ul_responses, &ul_responses_avg);
    
    //根据ip,port查找对应的合并列表，若需要合并，修改port信息
    i_hash_key_len = __frhash_related_make_key(p_stat_node->ui_ip, p_stat_node->us_port, arr_hash_key, sizeof(arr_hash_key));
    if (i_hash_key_len == 0)
    {
        //不可能发生
        return 1;
    }
    
    p_st_node = frhash2_getStr(&g_st_hash_related, arr_hash_key, i_hash_key_len);
    if (p_st_node)
    {
        //在关联hash中找到此节点，用关联的内容存储
        Port_related *p_st_related = (Port_related *)p_st_node->data;
        ui_ip = p_st_related->ui_ip_related;
        us_port = p_st_related->us_port_related;
    }
    else
    {
        ui_ip = p_stat_node->ui_ip;
        us_port = p_stat_node->us_port;
    }
    
    //添加到打印的hash中
    __frstat_outhash_add(p_st_hash_print, ui_ip, us_port, p_stat_node->i_l7_proto
                       , p_stat_node->st_conns_total.ul_connections
                       , p_stat_node->st_conns_total.ul_requests
                       , p_stat_node->st_conns_total.ul_responses
                       , ul_connections_avg, ul_requests_avg, ul_responses_avg);
    return 1;
}

/*******************************************************************************
*  FUNC     :  显示服务节点所有的信息
*  ARGS     :  pp_result            线程的所有信息
*  RTN      :  
*  NOTE     :  pp_result需要外面释放
*******************************************************************************/
void frstat_server_output(char **pp_result)
{
    char *p_outbuff = NULL;
    Frhash_header st_related;

    if(g_i_flag_init == FR_FAIL)
        return ;

    if (frhash2_create(&st_related, st_apm_params.ui_stat_server_hash_size) != FR_SUCC)
        return;
    
    pthread_rwlock_rdlock(&g_stat_server_rwlock);
    
    frhash2_run(&g_st_hash_server, &st_related, __frstat_do_related);
    
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    
    frhash2_show_all2(&st_related, &p_outbuff, __frstat_server_output);
    frhash2_free(&st_related, __outhash_node_free);
    
    if(pp_result == NULL)
    {
        frdbg("==========================\n");
        printf("output stat\n%s\n", p_outbuff);
        frdbg("==========================\n");
        frfree(p_outbuff);
        return;
    }
    
    *pp_result = p_outbuff;
    
    return;
}

/*******************************************************************************
*  FUNC     :  初始化服务节点信息
*  ARGS     :  i_timeout        每次做平均的间隔时间
*  RTN      :  FR_SUCC   (成功)
*              FR_FAIL   (失败)
*  NOTE     :  调用count,output,add都需要先运行过init (只运行一次)
*******************************************************************************/
int frstat_server_init(int i_timeout)
{
    if (pthread_rwlock_init(&g_stat_server_rwlock, NULL) != 0)
    {
        FRLOG_ERROR_DETAIL("pthread_rwlock_init failed");
        return FR_FAIL;
    }
    
    if (frhash2_create(&g_st_hash_server, st_apm_params.ui_stat_server_hash_size) != FR_SUCC)
    {
        FRLOG_ERROR_DETAIL("frhash2_create failed");
        return FR_FAIL;
    }
    
    if (frhash2_create(&g_st_hash_related, st_apm_params.ui_stat_server_hash_size) != FR_SUCC)
    {
        FRLOG_ERROR_DETAIL("frhash2_create failed");
        return FR_FAIL;
    }
    
    g_i_timeout = i_timeout;
    g_i_flag_init = FR_SUCC;
    
    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  退出服务节点信息
*  ARGS     :  
*  RTN      :  
*  NOTE     :  调用完init后，使用完调用exit  (只能运行一次)
*******************************************************************************/
void frstat_server_destory(void)
{
    if(g_i_flag_init == FR_FAIL)
        return;

    pthread_rwlock_wrlock(&g_stat_server_rwlock);
    frhash2_free(&g_st_hash_server, __server_node_free);
    frhash2_free(&g_st_hash_related, __related_node_free);
    pthread_rwlock_unlock(&g_stat_server_rwlock);
    
    pthread_rwlock_destroy(&g_stat_server_rwlock);

    g_i_flag_init = FR_FAIL;
    return;
}
